<?php
// TODO: реализовать возможность установления фильтров через множественные объекты: $articles->filter()->category(501)->sdate('>now') - предусмотреть вариант возвращения пустого результата

class articles
{

   private $articles = array();
   private $order    = NULL;
   private $limit    = TRUE;
   private $sanitize = array();
   
   /**
    * Set filter for outputs
    * TYPES: category (this will search with recursion under given category),
    *        field
    * array('type'=>
    *    array('field'=>
    *       array('type(filter)'=>'exact,between,less,more,not,like,have,nothave',
    *             'value'=>'value', // can be array
    *             'range'=>'value of range')));
    *
    * EXAMPLES:
    * $set['field']['cat'] = array('type' => 'exact', 'value' => 501);
    * $set['field']['cat'] = array('type' => 'have', 'value' => array(500,501));
    *
    * @param array $set
    * @return bool
    */
   public function setFilter($set = false)
   {
      if($set == false)
      {
         # DEFAULT FILTERING
         $this->sanitize = array();
         $this->sanitize['deleted'] = '`deleted` IS NULL';
         return true;
      }

      if(!empty($set['deleted']))
      {
         $this->sanitize['deleted'] = '`deleted` IS NOT NULL';
      } else
      {
         $this->sanitize['deleted'] = '`deleted` IS NULL';
      }

      if(isset($set['field']) && is_array($set['field']))
      {
         foreach($set['field'] AS $field=>$params)
         {
            # CHECK IF FIELD EXISTS
            $_F = fields::getInstance();
            if($field != 'cat' && $field != 'id' && !$_F->isFieldExist($field, 'a')) continue;
            
            $tmp = ' `'. $field .'` ';

            # SET PAGE LIMITS ACCORDING TO NODE PRESETS
            if($this->limit == TRUE && $field == 'cat' && $params['type'] == 'exact' && is_numeric($params['value']))
            {
               $node = tree_static::getNode($params['value']);
               paginator::setItemsOnPage($node->i_onpage);
            }

            # MAKE SQL CONDITIONS
            switch($params['type'])
            {
               case 'exact':
               case 'not':
                  if(is_array($params['value']))
                  {
                     if($params['type'] == 'not') $tmp .= 'NOT';
                     $tmp .= ' IN ("'. implode('", "', array_map('mysql_real_escape_string', $params['value'])) .'") ';
                  } else
                  {
                     if($params['type'] == 'not') $tmp .= '!';
                     $tmp .= '= "'. mysql_real_escape_string($params['value']) .'" ';
                  }
                  break;



               case 'have':
               case 'nothave':
                  if(is_array($params['value']))
                  {
                     $tmp = array();
                     foreach($params['value'] AS $value)
                     {
                        $tmp[] = ($params['type'] == 'nothave' ? 'NOT' : '') .' FIND_IN_SET("'. mysql_real_escape_string($value) .'", `'. $field .'`)';
                     }
                     if($params['type'] == 'nothave')
                     {
                        $tmp = '('. implode(' AND ', $tmp) .')';
                     } else
                     {
                        $tmp = '('. implode(' OR ', $tmp) .')';
                     }
                  } else
                  {
                     $tmp = ' FIND_IN_SET("'. mysql_real_escape_string($params['value']) .'", `'. $field .'`)';
                  }
                  break;



               case 'less':
               case 'more':
                  (string)$params['value'];
                  if($params['type'] == 'less') $tmp .= ' < ';
                  if($params['type'] == 'more') $tmp .= ' > ';
                  $tmp .= ' "'. mysql_real_escape_string($params['value']) .'"';
                  break;
                  
                  
                  
               case 'between':
                  (string)$params['value'];
                  $params['range'] = !empty($params['range']) ? (string)$params['range'] : $params['value'];
                  $tmp .= ' BETWEEN "'. mysql_real_escape_string($params['value']) .'" AND "'. mysql_real_escape_string($params['range']) .'"';
                  break;

               // TODO: фильтры по типу between, like
            }
            
            # ADD BIND GETTER FOR ARTICLES
            if($field == 'cat' && config::read('fetch_bind_articles', 'system'))
            {
               $tmp = '('. $tmp .' OR `id` IN (SELECT `node` FROM `meccano_binds` WHERE `bind_belong` = "c" AND `bind` ';
               switch($params['type'])
               {
                  case 'exact':
                  case 'not':
                     if(is_array($params['value']))
                     {
                        if($params['type'] == 'not') $tmp .= ' NOT ';
                        $tmp .= ' IN ("'. implode('", "', array_map('mysql_real_escape_string', $params['value'])) .'") ';
                     } else
                     {
                        if($params['type'] == 'not') $tmp .= '!';
                        $tmp .= '= "'. mysql_real_escape_string($params['value']) .'" ';
                     }
                     break;
                     
                  default:
                     $tmp .= ' = 0 ';
               }
               $tmp .= ')) ';
            }

            $this->sanitize[$field] = $tmp;
         }
      }

      # FILTER BY TAG
      if(isset($set['tag']))
      {
         $sql = '`id` IN 
            (SELECT `t1`.`aid`
               FROM `meccano_tags2content` AS `t1`, `meccano_tags` AS `t2`
               WHERE `t2`.`id` = `t1`.`tid` AND `t2`.`title` = "'. mysql_real_escape_string($set['tag']) .'"
            )';
         $this->sanitize['tag'] = $sql;
      }
      
      return TRUE;
   }

   /**
    * Set Output ordering
    * @param string $set
    */
   public function setOrder($set = NULL)
   {
      if($set == NULL)
      {
         $this->order = NULL;
      } elseif($set == 'random')
      {
         $set = 'RAND()';
         // TODO: переделать - чтобы рандом делался из выборки ID
      } else
      {
         $this->order = ' ORDER BY '. $set;
      }
   }

   public function getArticles($set = false)
   {
      if($set) $this->setFilter($set);
      $DB = database::getInstance();

      # QUERIES ARE SEPARATED TO ALLOW EXACT PAGE'S LIMIT SELECTION
      $sql = 'SELECT SQL_CALC_FOUND_ROWS *
         FROM `meccano_articles` WHERE ';
      if(is_array($this->sanitize) && count($this->sanitize) > 0) $sql .= implode(' AND ', $this->sanitize);
      if($this->order != FALSE) $sql .= $this->order;
      if($this->limit) $sql .= ' LIMIT '. ((paginator::getCurrentPage() - 1)* paginator::getItemsOnPage ()) .', '. paginator::getItemsOnPage();
      //echo $sql; exit();
      $DB->sql    = $sql;
      $main_table = $DB->DB_Fetch();

      $DB->sql = 'SELECT FOUND_ROWS()';
      $found = $DB->DB_FetchFlat();
      $found = reset($found);
      paginator::setPages($found);

      if(!empty($main_table))
      {
         $tmp = array();
         for($i=0, $t=sizeof($main_table); $i<$t; $i++)
         {
            $tmp[$main_table[$i]['id']] = $main_table[$i];
         }
         $main_table = $tmp;

         $sql = 'SELECT * FROM `meccano_articles_translate` WHERE `id` IN ('. implode(',', array_keys($main_table)) .')';
         $DB->sql = $sql;

         $trans_table = $DB->DB_Fetch();
         $tmp = array();
         for($i=0, $t=sizeof($trans_table); $i<$t; $i++)
         {
            $tmp[$trans_table[$i]['id']][$trans_table[$i]['lang']] = $trans_table[$i];
         }
         $trans_table = $tmp;

         # MERGE ARTICLE'S DATA
         foreach($main_table AS $id=>$a)
         {
            $data = empty($trans_table[$id]) ? array() : $trans_table[$id];

            foreach($data AS $l=>$value)
            {
               $data[$l] = array_merge($value, $a);
            }

            $this->articles[$id] = new article();
            $this->articles[$id]->loadFromArray($data);
         }
      }

      return $this->articles;
   }

   
   public function getList($set = false)
   {
      $this->limit = FALSE;
      if($set) $this->setFilter($set);
      
      $DB = database::getInstance();

      # QUERIES ARE SEPARATED TO ALLOW EXACT PAGE'S LIMIT SELECTION
      $sql = 'SELECT SQL_CALC_FOUND_ROWS *
         FROM `meccano_articles`, `meccano_articles_translate` WHERE ';
      if(is_array($this->sanitize) && count($this->sanitize) > 0) $sql .= implode(' AND ', $this->sanitize);
      $sql .= ' AND `meccano_articles`.`id` = `meccano_articles_translate`.`id` AND `meccano_articles_translate`.`lang` = '. request::getLang('currentId');
      if($this->order != FALSE) $sql .= $this->order;
      if($this->limit) $sql .= ' LIMIT '. ((paginator::getCurrentPage() - 1)* paginator::getItemsOnPage ()) .', '. paginator::getItemsOnPage();
      $DB->sql    = $sql;

      $data     = $DB->DB_Fetch();
      $articles = array();

      if(!empty($data))
      {
         foreach($data AS $value)
         {
            $articles[] = array(
               'id'    => $value['id'],
               'cat'   => $value['cat'],
               'title' => $value['title']
            );
         }
      }

      $this->limit = TRUE;

      return $articles;
   }


   /**
    * Delete articles for REAL
    *
    * @param array $ids
    * @return boolean
    */
   public function delete($ids)
   {
      (array)$ids;
      $ids = array_filter($ids, 'is_numeric');
      if(empty($ids)) return FALSE;
      $filter   = array('deleted' => true, 'field' => array('id' => array('type' => 'exact', 'value' => $ids)));
      $delete = $this->getArticles($filter);

      if(!empty($delete))
      {
         foreach($delete AS $del)
         {
            $del->delete();
         }
         $DB = database::getInstance();
         $DB->sql = 'DELETE `t1`.*, `t2`.*
            FROM `meccano_articles` AS `t1`, `meccano_articles_translate` AS `t2`
            WHERE `t1`.`id` IN (' . implode(', ', array_keys($delete)) . ')
               AND `t1`.`id` = `t2`.`id`';
         $DB->DB_Query();

         return TRUE;
      }

      return FALSE;
   }


   public function recovery($ids)
   {
      (array)$ids;
      $ids = array_filter($ids, 'is_numeric');
      if(empty($ids)) return FALSE;

      # TODO: проиндексировать статьи после восстановления.
      
      $DB = database::getInstance();
      $DB->sql = 'UPDATE `meccano_articles` SET `deleted` = NULL WHERE `id` IN (' . implode(', ', $ids) . ')';
      $DB->DB_Query();
   }
}